import type { CSSProperties, InjectionKey, Ref } from "vue";
import type { BoxSelect, ConfigurationType, ContextmenuItem, GridLineExpose, SvgInfo } from "/@/Configuration/types";
import type {
  DevicePanelInfo,
  LabelValuePanelInfo,
  PipePathPanelInfo,
  PipePathStyle,
  FlowPathPanelInfo,
  UpdatePanelOptions,
} from "/@/Configuration/AttrPanel/types";
import { Condition } from "../Configuration/ConditionPanel/types";

export interface Point {
  x: number;
  y: number;
}

export interface PipePathPoint extends Point {
  id: string;
  //重叠id，拥有同一个重叠id的节点永远重叠在一起；每当在同一个节点新增第2段子路径时，就会多一个重叠点id，
  //之后在这个节点上新增的路径段的父节点都会拥有这个重叠id；
  overlapId?: string;
  //是否父节点
  isParentNode?: boolean;
  //绑定的路径段描述文字的id
  bindTextIds?: string[];
  //是否反向路径的点
  isReverse?: boolean;
  _x: number;
  _y: number;
}

export interface PipePathText {
  id: string;
  startIndex: number;
  endIndex: number;
  value: string;
  width: number;
  height: number;
  initValue?: string;
  position: TextPosition;
  editable: boolean;
}

export enum PipePathType {
  flat = "flat",
  pipe = "pipe",
}

export enum PipePathSpeed {
  slow,
  normal,
  middle,
  fast,
}

export interface ToggleSelectData<T = any> {
  type: ConfigurationType;
  selected: boolean;
  index: number;
  unSelect?: () => void;
  multiple?: boolean;
  id?: string;
  drag?: {
    startData?: T;
    start?: () => T;
    move: (options: DragMoveOptions<T>) => void;
    end?: () => void;
  };
  getPipePathInfo?: () => PipePathPanelInfo;
  getDeviceInfo?: () => DevicePanelInfo;
  getLabelValueInfo?: () => LabelValuePanelInfo;
  getFlowPathInfo?: () => FlowPathPanelInfo;
}

export interface DragMoveOptions<T = any> {
  dx?: number;
  dy?: number;
  startData?: T;
  x?: number;
  y?: number;
  connectPoints?: Point[];
}

export interface Drag {
  id: string;
  type: ConfigurationType;
  startData?: any;
  start?: () => Point;
  move: (options: DragMoveOptions) => void;
  end?: () => void;
  extra?: {
    connectPositionIndex?: number;
  };
}

export interface Connection {
  isConnect: (id: string) => boolean;
  getConnect: (id: string) => Drag[] | undefined;
  connect: (id: string, drag: Drag) => void;
  clear: () => void;
  disConnect: (id: string, exceptId?: string) => void;
  startTogether: (id: string, exceptId?: string | string[]) => void;
  moveTogether: (id: string, options: DragMoveOptions, exceptId?: string | string[]) => void;
  endTogether: (id: string, exceptId?: string | string[]) => void;
  getData: () => ConnectionData;
}

export interface ConnectionData {
  [key: string]: Drag[];
}

//子组件之间或子组件与父亲的通讯对象
export interface CompCommon<T = any> {
  isEditor: Ref<boolean>;
  draggingPipePathRect?: PipePathPoint | null;
  connectingDevice?: Drag | null;
  initSvgInfo: (e: {
    svgEl: HTMLElement;
    boxSelectEl: SVGRectElement | null;
    gridLineIns: GridLineExpose | null;
  }) => void;
  getSvgInfo: () => SvgInfo | undefined;
  deleteCompItem: (id: string) => void;
  showContextmenu: (e: MouseEvent, options: { data?: ContextmenuItem[]; id?: string; element?: SVGElement }) => void;
  connection: Connection;
  toggleSelect: <T = any>(data: ToggleSelectData<T>) => void;
  multipleSelect: {
    startTogether: (id: string, exceptId?: string | string[]) => boolean;
    moveTogether: (options: DragMoveOptions, exceptId?: string | string[]) => void;
    endTogether: (exceptId?: string | string[]) => void;
  };
  updatePanelInfo: (param: UpdatePanelOptions<T>) => void;
  toTop: (el: SVGElement) => void;
}

export const CompCommonKey: InjectionKey<CompCommon> = Symbol();

export interface DeviceJSON {
  id: string;
  componentName?: string;
  imgSrc?: string;
  imgName?: string;
  x: number;
  y: number;
  width: number;
  rotate: number;
  text?: string;
  textPosition?: TextPosition;
}

export interface PipePathJSON {
  id: string;
  points: PipePathPoint[];
  textData: PipePathText[];
  colors: string[];
  isFloating: boolean;
  isReverse: boolean;
  speed: PipePathSpeed;
  style: PipePathStyle;
  type: PipePathType;
  conditionData: Condition[];
  showArrow: boolean;
}

export interface LabelValueJSON {
  id: string;
  position: "vertical" | "horizontal";
  labelText: string;
  valueText: string;
  unitText: string;
  labelX: number;
  labelY: number;
  rotate: number;
  labelCssProps: CSSProperties;
  valueCssProps: CSSProperties;
  unitCssProps: CSSProperties;
  hideValue: boolean;
  hideUnit: boolean;
  hideLabel: boolean;
  hideBg: boolean;
  dataKey: string | null;
  conditionData: Condition[];
}

export interface FlowPathJSON {
  id: string;
  x: number;
  y: number;
  width: number;
  height: number;
  type: FlowPathType;
  rotate: number;
  text?: string;
}

export type CompDataItem = PipePathJSON | DeviceJSON | LabelValueJSON | FlowPathJSON;

/**
 * 管道路径连接信息 id:管道路径id;position:连接在设备的位置索引
 */
export type SubId = { id: string; position: number };
export type ConnectIds = { [id: string]: SubId[] };

export interface ConfigurationJSON {
  scaleFactor: number;
  connectIds: ConnectIds;
  compData: CompDataItem[];
}

export interface DisplayInfo {
  name: string;
}

export interface BoxInfo {
  x: number;
  y: number;
  width: number;
  height: number;
  maxX: number;
  maxY: number;
}

export interface ConfigurationInstance<T, K = any> {
  isInBoxSelect: (boxSelect: BoxSelect) => boolean;
  select: () => void;
  toJSON: () => T;
  setJSON: (data: T) => void;
  getDragInfo?: () => Drag;
  /**
   * 设置连接关系 管道路径实例独有方法
   * @param drag 设备的drag对象
   * @param subId 管道路径连接信息
   */
  setConnection?: (drag: Drag, subId: SubId) => boolean;
  /**
   * 处理绑定数据点的数据
   */
  handleData?: (data: Record<string, any>) => void;
  getConditionData?: () => Condition[];
  getDataKey?: () => string | null;
  setConditionData?: (data: Condition[]) => void;
  /**
   * 预览条件设置的效果
   */
  previewCondition: (condition: Partial<Condition>) => void;
  /**
   * 还原设置过的条件效果
   */
  restoreCondition: () => void;
  getDisplayInfo?: () => DisplayInfo;
  getOriginalProps: () => K;
  //获取布局盒子信息
  getBox: () => BoxInfo;
  //组件平移
  translate: (dx: number, dy: number) => void;
}

export interface ConfigurationInstanceObj {
  [key: string]: ConfigurationInstance<CompDataItem>;
}

export enum TextPosition {
  Top = "top",
  Left = "left",
  Bottom = "bottom",
  Right = "right",
}

export enum BaseCompType {
  ConfigureIcon = "ConfigureIcon",
}

export enum FlowPathType {
  Arrow = "Arrow",
  Diamond = "Diamond",
  DottedArrow = "DottedArrow",
  Triangle = "Triangle",
}

export enum LabelValuePart {
  Label = "Label",
  Value = "Value",
  Unit = "Unit",
}

export interface SelectEvent {
  e: MouseEvent | TouchEvent;
  type: ConfigurationType;
  id: string;
  componentName?: string;
  imgSrc?: string;
}
